package com.snap.vseries.service;

import android.os.Bundle;
import android.util.Log;

import com.orhanobut.logger.Logger;
import com.snap.vseries.AppConfig;
import com.snap.vseries.Constants;
import com.snap.vseries.analyze.AnalyzeManager;
import com.snap.vseries.bean.AnalysisProtocol;
import com.snap.vseries.bean.ExpEntity;
import com.snap.vseries.bean.ExpInfo;
import com.snap.vseries.logger.LoggerUtil;
import com.snap.vseries.manager.FileManager;
import com.snap.vseries.model.DBManager;
import com.snap.vseries.serial.SerialPortHelper;
import com.snap.vseries.utils.OkHttpUtil;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
 * 这个对象的生命周期 等于 app的生命周期
 */
public class ExpController implements IExp {
    private SerialPortHelper serialPortHelper;
    private static final String TAG = "ExpController";
    private ExecutorService executor = Executors.newCachedThreadPool();
    private List<OnExpStateChangedListener> stateChangedListeners = new ArrayList<>();
    private volatile int expState;
    private ProgramTask task;
    private Future<Boolean> future;
    private int deviceId;
    private PcrService.IFinishedListener finishedListener;

    public ExpController(SerialPortHelper serialPortHelper, int deviceId, PcrService.IFinishedListener finishedListener) {
        this.serialPortHelper = serialPortHelper;
        this.deviceId = deviceId;
        this.finishedListener = finishedListener;
    }

    public int getDeviceId() {
        return deviceId;
    }

    private void switchExpState(int newState) {
        expState = newState;
        Logger.e(deviceId + ":设备变成状态%d", newState);

        for (OnExpStateChangedListener listener : stateChangedListeners) {
            listener.onStateChanged();
        }
    }

    public int getExpState() {
        return this.expState;
    }

    public void setExpState(int state) {
        this.expState = state;
    }

    private void openSerialPortIfNeed() {
        try {
            serialPortHelper.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void startExp(ExpInfo expInfo) {
        LoggerUtil.Log(deviceId, expInfo.getName(), "***************** exp begin" + (new Date().toLocaleString()) + "*********************");
        openSerialPortIfNeed();
        task = new ProgramTask(serialPortHelper, expInfo, deviceId);
        switchExpState(Constants.EXP_STATE_RUNNING);
        future = executor.submit(task);
        executor.submit(() -> ExpController.this.monitorExp(expInfo));
    }

    private void monitorExp(ExpInfo expInfo) {
        int finishCause = Constants.EXP_FINISH_NORMALLY;
        try {
            Boolean result = future.get();
            if (result) {
                LoggerUtil.Log(deviceId, expInfo.getName(), "┌-------------------------------┐");
                LoggerUtil.Log(deviceId, expInfo.getName(), "┆   exp finish normally    ┆");
                LoggerUtil.Log(deviceId, expInfo.getName(), "└-------------------------------┘");
            }
        } catch (InterruptedException e) {
            finishCause = ExpException.ERROR_CODE_UNKNOWN;
        } catch (ExecutionException e) {
            e.printStackTrace();
            if (e.getCause() instanceof ExpException) {
                finishCause = ((ExpException) e.getCause()).errorCode;
            } else {
                finishCause = ExpException.ERROR_CODE_UNKNOWN;
            }
            LoggerUtil.Log(deviceId, expInfo.getName(), "┌-------------------------------------┐");
            LoggerUtil.Log(deviceId, expInfo.getName(), "┆   exp finish with exception    ┆");
            LoggerUtil.Log(deviceId, expInfo.getName(), "└-------------------------------------┘");
            LoggerUtil.Log(deviceId, expInfo.getName(), e.getCause().getMessage());
        } catch (CancellationException e) {
            finishCause = Constants.EXP_FINISH_MANUALLY;
            LoggerUtil.Log(deviceId, expInfo.getName(), "┌-------------------------------┐");
            LoggerUtil.Log(deviceId, expInfo.getName(), "┆    exp finish manually    ┆");
            LoggerUtil.Log(deviceId, expInfo.getName(), "└-------------------------------┘");
        } finally {
            task.finalOperation(finishCause);
            finallyHandler(expInfo, finishCause);
        }
    }

    private void finallyHandler(ExpInfo expInfo, int finishCause) {
        switchExpState(finishCause >= 0 ? Constants.EXP_STATE_INTERRUPT : Constants.EXP_STATE_FINISH);

        if (finishedListener != null) {
            finishedListener.onFinished();
        }
        saveExp(expInfo, finishCause);
        try {
            expInfo = FileManager.getInstance().getExpDataByName(expInfo.getName());
            if (expInfo.getProtocols() == null || expInfo.getProtocols().size() == 0) {
                List<AnalysisProtocol> protocols = new ArrayList<>();
                protocols.add(new AnalysisProtocol());
                protocols.add(new AnalysisProtocol());
                protocols.add(new AnalysisProtocol());
                protocols.add(new AnalysisProtocol());
                expInfo.setProtocols(protocols);
                expInfo.setAnalyzed(false);
            }
            AnalyzeManager.doAnalyze(expInfo);
            postResult(expInfo);
        } catch (Exception e) {
            Logger.e("postResult失败：" + e.getMessage());
            try {
                Logger.e("ApiData:postResult第二次尝试");
                String url = "http://apicms.edengene.com.cn/api/tt/post";
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss", Locale.CHINA);
                String jsonString = "{\"deviceid\": \"MOLE123456" + AppConfig.DEVICES[deviceId] + "\", \"time\": \"" + format.format(new Date()) + "\", \"nameK1\": \"510101\", \"k1_ct\": \"" + "重新取样进行测试" + "\", \"k1_ag\": \"" + "重新取样进行测试" + "\"}";
                RequestBody body = FormBody.create(MediaType.parse("application/json;charset=utf-8"), jsonString);
                Logger.e("ApiData:开始发送数据" + jsonString);
                OkHttpUtil.getHttpRequest(url, body);
            } catch (Exception e1) {
                Logger.e("postResult失败：" + e1.getMessage());
            }
        }
        //输出结束语句
        LoggerUtil.Log(deviceId, expInfo.getName(), "***************** exp end:" + (new Date().toLocaleString()) + "*********************");
    }

    public void postResult(ExpInfo experimentInfo) {
        Logger.e("ApiData:postResult");
        String url = "http://apicms.edengene.com.cn/api/tt/post";
        //        JSONObject jsonObject = new JSONObject();
//        try {
//            jsonObject.put("deviceid",1111111);//填写你们设备内部的编码，为了保险起见，传输给我们的时候，加上你们的公司简称全拼，具体简称与因顿沟通确认；
//            jsonObject.put("name","顺");
//            jsonObject.put("studentId","123123");
//            jsonObject.put("sex","小萌新");
//            jsonObject.put("data","I have pan");
//
//        } catch (JSONException e) {
//            e.printStackTrace();
//        }
        if (experimentInfo == null || experimentInfo.getHoleInfo() == null || experimentInfo.getHoleInfo().getChannelData() == null) {
            return;
        }
        float fam = experimentInfo.getHoleInfo().getChannelData().get(0).getCtValue();
        float vic = experimentInfo.getHoleInfo().getChannelData().get(1).getCtValue();
        float rox = experimentInfo.getHoleInfo().getChannelData().get(2).getCtValue();
        float cy5 = experimentInfo.getHoleInfo().getChannelData().get(3).getCtValue();
        String CT;
        String AG;
        if (fam < 35 && (vic >= 35 || vic == 0)) {
            CT = "C/C";
        } else if ((fam >= 35 || fam == 0) && vic < 35) {
            CT = "T/T";
        } else if (fam < 38 && vic < 38) {
            CT = "C/T";
        } else {
            CT = "重新取样进行测试";
        }
        if (rox < 36 && (cy5 >= 36 || cy5 == 0)) {
            AG = "G/G";
        } else if ((rox >= 36 || rox == 0) && cy5 < 36) {
            AG = "A/A";
        } else if (rox < 38 && cy5 < 38) {
            AG = "G/A";
        } else {
            AG = "重新取样进行测试";
        }

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss", Locale.CHINA);
        String jsonString = "{\"deviceid\": \"MOLE123456" + AppConfig.DEVICES[deviceId] + "\", \"time\": \"" + format.format(new Date()) + "\", \"nameK1\": \"510101\", \"k1_ct\": \"" + CT + "\", \"k1_ag\": \"" + AG + "\"}";
        RequestBody body = FormBody.create(MediaType.parse("application/json;charset=utf-8"), jsonString);
        Logger.e("ApiData:开始发送数据" + jsonString);
        OkHttpUtil.getHttpRequest(url, body);
    }

    private void saveExp(ExpInfo expInfo, int finishCause) {
        if (expInfo == null) return;
        String expName = expInfo.getName();
        LoggerUtil.Log(deviceId, expInfo.getName(), "%s 开始记录文件");

        long endTime = System.currentTimeMillis();
        Bundle bundle = task.getRunSummary();
        int runCycle = bundle.getInt("totalRunCycleCount");
        long beginTime = bundle.getLong("beginTime");

        expInfo.setEndTime(endTime);
        expInfo.setRunCycle(runCycle);
        expInfo.setFinishCause(finishCause);
        expInfo.setProcessData(task.getProcessData());
        boolean expFileSaved = FileManager.getInstance().saveExpData(expInfo);
        if (expFileSaved) {
            ExpEntity entity = new ExpEntity();
            entity.setTemplate(false);
            entity.setDeviceTag(expInfo.getDeviceTag());

            entity.setName(expName);
            entity.setStartTime(beginTime);
//            entity.setEndTime(end);
            //实验文件存储成功，再把信息写入数据库
            Log.e("Rachel_test", "开始记录数据库");
            LoggerUtil.Log(deviceId, expInfo.getName(), "%s 开始记录数据库");
            DBManager.get().saveExpSync(entity);
            LoggerUtil.Log(deviceId, expInfo.getName(), "%s 文件记录成功");
        } else {
            LoggerUtil.Log(deviceId, expInfo.getName(), "%s 文件记录失败");
        }
    }


    /**
     * 手动停止
     */
    @Override
    public void stopExp() {
        if (task == null) {
            return;
        }
        future.cancel(true);
    }

    public Bundle getRunSummary() {
        return task.getRunSummary();
    }

    public ExpInfo getExpInfo() {
        if (task == null) {
            return null;
        }
        return task.getExperimentInfo();
    }

    public void registerOnExpStateChangedListener(OnExpStateChangedListener listener) {
        stateChangedListeners.add(listener);
    }

    public void unregisterOnExpStateChangedListener(OnExpStateChangedListener listener) {
        stateChangedListeners.remove(listener);
    }

    public void setOnIntensityListener(OnIntensityListener onIntensityListener) {
        if (task != null) {
            task.setOnIntensityListener(onIntensityListener);
        }
    }

    public void setOnSectionProcessListener(OnSectionProcessListener listener) {
        if (task != null) {
            task.setOnSectionProcessListener(listener);
        }
    }
}
